//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<CColorRenderTarget10.cpp>
///	@path	e:\xeres\src\graphics\dx10/
///	@date	2009/01/01
///	@desc	.

#include "config/config.h"

#include "lib/system/thread_debug.h"
#include "lib/math/math_win32.h"

#include "graphics/DxHelpers.h"
#include "graphics/dx10/CColorRenderTarget10.h"

namespace xeres {

	IMPL_IOBJECT_CLASS( CColorRenderTarget10 );
	
	// CColorRenderTarget10
	CColorRenderTarget10::CColorRenderTarget10( ID3D10Texture2D * tex , 
		ID3D10RenderTargetView * renderTarget , ID3D10ShaderResourceView * shaderView )
		: m_pTexture( tex )
		, m_pRtView( renderTarget )
		, m_pShaderView( shaderView )
	{
		m_pTexture->GetDesc( &m_texDesc );
		m_pRtView->GetDesc( &m_rtDesc );
		if( m_pShaderView )
		{
			m_pShaderView->GetDesc( &m_shaderDesc );
		}
		else
		{
			memset( &m_shaderDesc , 0 , sizeof(D3D10_SHADER_RESOURCE_VIEW_DESC) );
		}
	}
	// ~CColorRenderTarget10
	CColorRenderTarget10::~CColorRenderTarget10( void )
	{
		if( m_pRtView )
		{
			UINT rest = m_pRtView->Release();
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CColorRenderTarget10::DTOR: Invalid ID3D10RenderTargetView reference count.") );
				FATAL_ABORT( _S("Invalid ID3D10ShaderResourceView reference count.") );
			}
			m_pRtView = NULL;
		}
		if( m_pShaderView )
		{
			UINT rest = m_pShaderView->Release();
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CColorRenderTarget10::DTOR: Invalid ID3D10Texture2D reference count.") );
				FATAL_ABORT( _S("Invalid ID3D10ShaderResourceView reference count.") );
			}
			m_pShaderView = NULL;
		}
		if( m_pTexture )
		{
			UINT rest = m_pTexture->Release();
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CColorRenderTarget10::DTOR: Invalid ID3D10Texture2D reference count.") );
				FATAL_ABORT( _S("Invalid ID3D10Texture2D reference count.") );
			}
			m_pTexture = NULL;
		}
	}
	// OnLostDevice
	bool CColorRenderTarget10::OnLostDevice( void )
	{
		// render target needs to reset
		if( m_pRtView )
		{
			UINT rest = m_pRtView->Release();
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CColorRenderTarget10::DTOR: Invalid ID3D10RenderTargetView reference count.") );
				FATAL_ABORT( _S("Invalid ID3D10ShaderResourceView reference count.") );
			}
			m_pRtView = NULL;
		}
		if( m_pShaderView )
		{
			UINT rest = m_pShaderView->Release();
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CColorRenderTarget10::DTOR: Invalid ID3D10Texture2D reference count.") );
				FATAL_ABORT( _S("Invalid ID3D10ShaderResourceView reference count.") );
			}
			m_pShaderView = NULL;
		}
		if( m_pTexture )
		{
			UINT rest = m_pTexture->Release();
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CColorRenderTarget10::OnLostDevice: Invalid ID3D10Texture2D reference count.") );
				FATAL_ABORT( _S("Invalid ID3D10Texture2D reference count.") );
			}
			m_pTexture = NULL;
		}
		return true;
	}
	// OnResetDevice
	bool CColorRenderTarget10::OnResetDevice( RefWeak<IDevice> device )
	{
		RefWeak<CDevice10> d3d10 = device;
		HRESULT hr = d3d10->GetDevice()->CreateTexture2D( &m_texDesc , NULL , &m_pTexture );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::OnResetDevice: Failed to re-create render target texture: %s") , d3d_get_err(hr) );
			return false;
		}
		hr = d3d10->GetDevice()->CreateRenderTargetView( m_pTexture , &m_rtDesc , &m_pRtView );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::OnResetDevice: Failed to re-create render target: %s") , d3d_get_err(hr) );
			return false;
		}
		if( m_shaderDesc.Format != DXGI_FORMAT_UNKNOWN )
		{
			hr = d3d10->GetDevice()->CreateShaderResourceView( m_pTexture , &m_shaderDesc , &m_pShaderView );
			if( FAILED(hr) )
			{
				TRACE_ERROR( _S("CColorRenderTarget10::OnResetDevice: Failed to re-create render target shader view: %s") , d3d_get_err(hr) );
				return false;
			}
		}
		return true;
	}

	// GetType
	TextureType CColorRenderTarget10::GetType( void )
	{
		return TEXTURE_2D;
	}

	// GetFormat
	DXFormat CColorRenderTarget10::GetFormat( void )
	{
		return DXFormat( m_texDesc.Format );
	}

	// GetSize
	Pair<int> CColorRenderTarget10::GetSize( void )
	{
		return Pair<int>( m_texDesc.Width , m_texDesc.Height );
	}

	// GetDepth
	size_t CColorRenderTarget10::GetDepth( void )
	{
		FATAL_ABORT( _S("Try to get depth from 2D texture.") );
		return 0;
	}

	// IsWritable
	bool CColorRenderTarget10::IsWritable( void )
	{
		return (m_texDesc.CPUAccessFlags & D3D10_CPU_ACCESS_WRITE) ? true : false;
	}

	// IsReadable
	bool CColorRenderTarget10::IsReadable( void )
	{
		return (m_texDesc.CPUAccessFlags & D3D10_CPU_ACCESS_READ) ? true : false;
	}

	// Map
	bool CColorRenderTarget10::Map( uint sub , ResourceMap& data )
	{
		if( m_pTexture == NULL )
			return false;

		if( sub >= m_texDesc.MipLevels )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::Map: Level exceeded limit.") );
			return false;
		}

		if( ( m_texDesc.CPUAccessFlags & D3D10_CPU_ACCESS_WRITE ) == 0 )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::Map: Texture cannot be accessed by CPU.") );
			return false;
		}

		D3D10_MAPPED_TEXTURE2D mapped;
		memset( &mapped , 0 , sizeof(D3D10_MAPPED_TEXTURE2D) );
		HRESULT hr = m_pTexture->Map( sub , D3D10_MAP_WRITE_DISCARD , 0 , &mapped );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::Map: Failed to lock texture: %s") ,
				d3d_get_err(hr) );
			return false;
		}
		size_t total = dxgi_get_color_size( m_texDesc.Format ) * m_texDesc.Height * mapped.RowPitch;
		data.Map( (byte*)mapped.pData , total , mapped.RowPitch , m_texDesc.Height , m_texDesc.Width );
		return true;
	}

	// ReadBack
	bool CColorRenderTarget10::ReadBack( uint sub , ResourceMap& data , bool readonly )
	{
		
		if( m_pTexture == NULL )
			return false;

		if( sub >= m_texDesc.MipLevels )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::ReadBack: Level exceeded limit.") );
			return false;
		}

		if( ( m_texDesc.CPUAccessFlags & D3D10_CPU_ACCESS_READ ) == 0 )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::ReadBack: Texture cannot be accessed by CPU.") );
			return false;
		}
		if( !readonly && ( ( m_texDesc.CPUAccessFlags & D3D10_CPU_ACCESS_WRITE ) == 0 ) )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::ReadBack: Texture cannot be accessed by CPU.") );
			return false;
		}

		D3D10_MAPPED_TEXTURE2D mapped;
		memset( &mapped , 0 , sizeof(D3D10_MAPPED_TEXTURE2D) );
		HRESULT hr = m_pTexture->Map( sub , readonly ? D3D10_MAP_READ : D3D10_MAP_READ_WRITE , 0 , &mapped );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CColorRenderTarget10::ReadBack: Failed to lock texture: %s") ,
				d3d_get_err(hr) );
			return false;
		}
		size_t total = dxgi_get_color_size( m_texDesc.Format ) * m_texDesc.Height * mapped.RowPitch;
		data.Map( (byte*)mapped.pData , total , mapped.RowPitch , m_texDesc.Height , m_texDesc.Width );
		return true;
	}

	// Unmap
	bool CColorRenderTarget10::Unmap( uint sub )
	{
		if( m_pTexture == NULL )
			return false;
		
		m_pTexture->Unmap( sub );
		return true;
	}

	// Update
	bool CColorRenderTarget10::Update( uint sub , const Box<uint>& size , const byte * data , uint row_pitch , uint depth_pitch )
	{
		return false;
	}

	// ApplyTarget
	bool CColorRenderTarget10::ApplyTarget( RefWeak<IDevice> device )
	{
		RefWeak<CDevice10> d3d10 = device;
		ID3D10RenderTargetView * pRTV = NULL;
		ID3D10DepthStencilView * pDSV = NULL;
		d3d10->GetDevice()->OMGetRenderTargets( 1 , &pRTV , &pDSV );
		d3d10->GetDevice()->OMSetRenderTargets( 1 , &m_pRtView , pDSV );
		if( pRTV ) pRTV->Release();
		if( pDSV ) pDSV->Release();
		return true;
	}

	// GetTextureInterface
	IUnknown * CColorRenderTarget10::GetTextureInterface( void )
	{
		return m_pShaderView ? (IUnknown*)m_pShaderView : (IUnknown*)m_pTexture;
	}

	// GetRenderTargetInterface
	IUnknown * CColorRenderTarget10::GetRenderTargetInterface( void )
	{
		return m_pRtView;
	}



} // namespace xeres
